package com.example.ormsqlsplicingframe1.orm.jdbc;


import com.example.ormsqlsplicingframe1.orm.registry.Registry;
import io.swagger.annotations.ApiModel;
import lombok.SneakyThrows;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.*;


@ApiModel("sql执行器")
public class SelectWrapperJdbc {


    public SelectWrapperJdbc() {
    }


    private static DataSource datasource;

    public SelectWrapperJdbc(DataSource datasource) {
        this.datasource = datasource;
    }


    private static Map<Class,Registry> map = new HashMap<>();


    public SelectWrapperJdbc importType(Registry registry){
        map.put(registry.getObj(),registry);
        return this;
    }



    public static Connection connection(){

        try {
            Connection connection = datasource.getConnection();

            return connection;
        }catch (Exception e){
            throw new RuntimeException("数据库连接失败:"+e.getMessage());
        }
    }

    //值类型
    private static Object encode(Object value){

        if (value.getClass() == String.class){
            return value;
        }
        if (value.getClass().isPrimitive()){
            return value;
        }
        if (value.getClass() == Integer.class){
            return value;
        }
        if (value.getClass() == Date.class){
            return value;
        }
        if (value.getClass() == Long.class) {
            return value;
        } else  {
            throw new RuntimeException("当前类型不匹配:"+value.getClass());
        }

    }

    //数据库类型转Java类型
    @SneakyThrows
    private static Object decode(String value,Field field){

        Registry registry = map.get(field.getType());

        if (registry == null){
            throw new RuntimeException("类型不兼容:"+field.getType());
        }

        return registry.decode(value,field);

    }

    @SneakyThrows
    public static int insert(String sql,List<Object> args)  {

        Connection connection = null;
        try {
            connection = connection();

            return insert(connection,sql,args);
        }finally {
            connection.close();
        }
    }

    @SneakyThrows
    private static int insert( Connection connection,String sql,List<Object> args) {

        PreparedStatement statement = null;

        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);

            for (int i = 0; i < args.size(); i++) {
                Object value = args.get(i);
                value = encode(value);
                statement.setObject(i+1,value);
            }

            String string = statement.toString();
            boolean isInsert =statement.execute();

            if (!isInsert) return 1;

            return 0;

        }finally {

            if (statement != null) statement.close();

            if (resultSet != null) resultSet.close();
        }


    }

    @SneakyThrows
    public static <E> List<E> select(String sql,List<Object> args,Class<E> obj)  {

        Connection connection = null;
        try {
            connection = connection();

            return select(connection,sql,args,obj);
        }finally {
            connection.close();
        }
    }


    @SneakyThrows
    private static <E> List<E> select( Connection connection,String sql,List<Object> args,Class<E> obj) {



        PreparedStatement statement = null;

        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);

            for (int i = 0; i < args.size(); i++) {
                Object value = args.get(i);

                value = encode(value);

                statement.setObject(i+1,value);

            }

            resultSet = statement.executeQuery();
            ResultSetMetaData metaData = resultSet.getMetaData();

            final ArrayList<Map<String, String>> arrayList = new ArrayList<>();

            while (resultSet.next()){
                final HashMap<String, String> map = new HashMap<>();
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    final String label = metaData.getColumnLabel(i);
                    final String value = resultSet.getString(label);
                    map.put(label,value);
                }
                arrayList.add(map);
            }

            List<E> list = getJaveObj(arrayList, obj);


            return list;

        }finally {

            if (statement != null) statement.close();

            if (resultSet != null) resultSet.close();
        }


    }


    @SneakyThrows
    public static <E> List<E> select(String sql,Object[] args,Class<E> obj)  {

        Connection connection = null;
        try {
            connection = connection();

            return select(connection,sql,args,obj);
        }finally {
            connection.close();
        }
    }
    /**
     * select id as username fron where id = ? and username = ? user_id
     * @param sql
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    @SneakyThrows
    private static <E> List<E> select( Connection connection,String sql,Object[] args,Class<E> obj) {


        PreparedStatement statement = null;

        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);

            for (int i = 0; i <args.length ; i++) {
                Object value = args[i];
                value = encode(value);
                statement.setObject(i+1,value);

            }

            resultSet = statement.executeQuery(sql);
            ResultSetMetaData metaData = resultSet.getMetaData();

            final ArrayList<Map<String, String>> arrayList = new ArrayList<>();

            while (resultSet.next()){
                final HashMap<String, String> map = new HashMap<>();
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    final String label = metaData.getColumnLabel(i);
                    final String value = resultSet.getString(label);
                    map.put(label,value);
                }
                arrayList.add(map);
            }

            final List<E> list = getJaveObj(arrayList, obj);


            return list;

        }finally {

            if (statement != null) statement.close();

            if (resultSet != null) resultSet.close();



        }


    }



    @SneakyThrows
    private static <E> List<E> getJaveObj(List<Map<String, String>> list, Class<E> clzss){

        List<E> arrayList  = new ArrayList<>();
        for (Map<String, String> map : list) {

            E newInstance = clzss.newInstance();
            for (Field field : clzss.getDeclaredFields()) {
                field.setAccessible(true);

                final String value = map.get(field.getName());
                Object obj =  decode(value,field);
                field.set(newInstance,obj);
            }

            arrayList.add(newInstance);

        }
        return arrayList;
    }


}
